# Copyright 2010 Felix Kerekes.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Contains data providers implementations and utilities.
"""

__authors__ = [
    '"Felix Kerekes" <sttwister@gmail.com>',
  ]


# pylint: disable=C0301
from string import FixedStringProvider
from string import RandomWordProvider
from string import RandomNameProvider
from string import RandomPhraseProvider
from boolean import FixedBooleanProvider
from boolean import RandomBooleanProvider
from integer import FixedIntegerProvider
from integer import RandomUniformDistributionIntegerProvider
from integer import RandomNormalDistributionIntegerProvider
from integer import SequenceIntegerProvider
from float import FixedFloatProvider
from float import RandomUniformDistributionFloatProvider
from float import RandomNormalDistributionFloatProvider
from datetime_provider import FixedDateTimeProvider
from datetime_provider import RandomUniformDistributionDateTimeProvider
from datetime_provider import RandomNormalDistributionDateTimeProvider
from date import FixedDateProvider
from date import RandomUniformDistributionDateProvider
from date import RandomNormalDistributionDateProvider
from user import FixedUserProvider
from user import RandomUserProvider
from text import RandomParagraphProvider
from text import RandomPlainTextDocumentProvider
from text import RandomHtmlDocumentProvider
from text import RandomMarkdownDocumentProvider
from link import FixedLinkProvider
from link import RandomLinkProvider
from email import FixedEmailProvider
from email import RandomEmailProvider
from phone_number import FixedPhoneNumberProvider
from phone_number import RandomPhoneNumberProvider
from reference import RandomReferenceProvider
from reference import FixedReferenceProvider
from list import EmptyListProvider
# pylint: enable=C0301


class Logic():
  """Logic class for general data provider functionality.
  """

  def __init__(self):
    self.providers = {}
    self.providers_data = self._getProvidersData()
    self.providers_mapping = self._getProvidersMapping()

  @staticmethod
  def getProviders():
    """Returns a mapping from GAE property name to compatible data providers.
    """

    providers = {}
    providers['StringProperty'] = [FixedStringProvider,
                                   RandomWordProvider,
                                   RandomNameProvider,
                                   RandomPhraseProvider]
    providers['BooleanProperty'] = [FixedBooleanProvider,
                                    RandomBooleanProvider]
    providers['IntegerProperty'] = [FixedIntegerProvider,
                                    RandomUniformDistributionIntegerProvider,
                                    RandomNormalDistributionIntegerProvider,
                                    SequenceIntegerProvider]
    providers['FloatProperty'] = [FixedFloatProvider,
                                  RandomUniformDistributionFloatProvider,
                                  RandomNormalDistributionFloatProvider]
    providers['DateTimeProperty'] = [FixedDateTimeProvider,
                                     RandomUniformDistributionDateTimeProvider,
                                     RandomNormalDistributionDateTimeProvider]
    providers['DateProperty'] = [FixedDateProvider,
                                 RandomUniformDistributionDateProvider,
                                 RandomNormalDistributionDateProvider]
    providers['UserProperty'] = [FixedUserProvider,
                                 RandomUserProvider]
    providers['BlobProperty'] = []
    providers['TextProperty'] = [RandomParagraphProvider,
                                 RandomPlainTextDocumentProvider,
                                 RandomHtmlDocumentProvider,
                                 RandomMarkdownDocumentProvider]
    providers['TextProperty'].extend(providers['StringProperty'])
    providers['LinkProperty'] = [FixedLinkProvider,
                                 RandomLinkProvider]
    providers['EmailProperty'] = [FixedEmailProvider,
                                  RandomEmailProvider]
    providers['PhoneNumberProperty'] = [FixedPhoneNumberProvider,
                                        RandomPhoneNumberProvider]
    providers['ReferenceProperty'] = [RandomReferenceProvider,
                                      FixedReferenceProvider]
    providers['_ReverseReferenceProperty'] = []
    providers['ListProperty'] = [EmptyListProvider]
    providers['StringListProperty'] = [EmptyListProvider]
    return providers

  def _getProvidersMapping(self):
    """Returns a dictionary mapping property names to possible data
    providers.
    """
    providers_mapping = {}
    mapping = self.getProviders()
    for prop_type, providers_list in mapping.items():
      providers_mapping[prop_type] = []

      for provider in providers_list:
        providers_mapping[prop_type].append(provider.__name__)
    return providers_mapping

  def getProvidersMapping(self):
    """Returned a cached copy of the providers mappings.
    """
    return self.providers_mapping

  def _getProvidersData(self):
    """Returns a list of dictionary describing data providers.
    """
    providers_data = []
    mapping = self.getProviders()

    for prop_type, providers_list in mapping.items():

      for provider in providers_list:

        provider_name = provider.__name__
        if not self.getProvider(provider_name):
          provider_data = {}

          provider_data['name'] = provider_name
          provider_data['description'] = provider.__doc__

          self.registerProvider(provider_name, provider)

          parameters = {}
          for parameter in provider.getParametersList():
            parameter_data = {}

            parameter_name = parameter.name
            parameter_data['name'] = parameter.name
            parameter_data['verbose_name'] = parameter.verbose_name
            parameter_data['description'] = parameter.description
            parameter_data['required'] = parameter.required

            parameters[parameter_name] = parameter_data

          provider_data['parameters'] = parameters

          providers_data.append(provider_data)

    return providers_data

  def getProvidersData(self):
    """Returned a cached copy of the providers data.
    """
    return self.providers_data

  def getProvider(self, provider_name):
    """Retrieves the class of a data provider that can be used for seeding.
    The data provider must first be registered with self.registerProvider().
    """
    return self.providers.get(provider_name, None)

  def registerProvider(self, provider_name, provider):
    """Registers a new data provider that can be used for seeding.
    """
    self.providers[provider_name] = provider


logic = Logic()
